﻿using System.IO;
using System.Collections.Generic;
using UnityEngine;
using VoxelBlock;

namespace VoxelBlock.VoxelInput
{
    public static class RioVoxelDataIO
    {
        public static void Save(string path, RioVoxelData data)
        {
            using (FileStream fs = new FileStream(path, FileMode.Create))
            {
                using (System.IO.BinaryWriter bw = new BinaryWriter(fs))
                {
                    bw.Write("riovox");
                    bw.Write(data.version);

                    
                    bw.Write(data.headDatas.Length);//头文件信息长度

                    for (int i = 0; i < data.headDatas.Length; i++)
                    {
                        bw.Write(data.headDatas[i].operationType);
                        bool isOpen = data.headDatas[i].isOpen;
                        bw.Write(data.headDatas[i].isOpen);
                        if (isOpen)
                        {
                            bw.Write(data.headDatas[i].operationData);
                        }
                    }

                    bw.Write(-1);//下一步读取的字节数量，-1代表直接读取， 大于0代表要读取出来解压或者解密


                    bw.Write(255);//下一步读取的颜色数量
                    for (int i = 0; i < 255; i++)
                    {
                        Color32 color = data.colors[i];
                        //保存颜色
                        bw.Write(color.r);
                        bw.Write(color.g);
                        bw.Write(color.b);
                    }
                    bw.Write(-2);//下一步读取的字节数量， -2 代表没有这个信息，直接跳过。本来这里要读取材质信息

                    bw.Write(data.transforms.Length);//下一步读取的字节数量，骨骼节点

                    //Tranform
                    for (int i = 0; i < data.transforms.Length; i++)
                    {
                        bw.Write(data.transforms[i].name);
                        bw.Write(data.transforms[i].layer);
                    }


                    //相对父对象的坐标
                    for (int m = 0; m < data.transforms.Length; m++)
                    {
                        Vector3 v = data.transforms[m].pivot;
                        bw.Write(v.x);
                        bw.Write(v.y);
                        bw.Write(v.z);
                    }

                    //相对父对象的坐标
                    for (int m = 0; m < data.transforms.Length; m++)
                    {
                        Vector3 v = data.transforms[m].localPosition;
                        bw.Write(v.x);
                        bw.Write(v.y);
                        bw.Write(v.z);
                    }

                    //相对父对象的旋转欧拉角
                    for (int m = 0; m < data.transforms.Length; m++)
                    {
                        Vector3 v = data.transforms[m].localEulerAngles;
                        bw.Write(v.x);
                        bw.Write(v.y);
                        bw.Write(v.z);
                    }

                    //相对父对象的缩放
                    for (int m = 0; m < data.transforms.Length; m++)
                    {
                        Vector3 v = data.transforms[m].localScale;
                        bw.Write(v.x);
                        bw.Write(v.y);
                        bw.Write(v.z);
                    }

                    //蒙皮参数
                    bw.Write(-2);//后面会考虑复杂的蒙皮参数

                    bw.Write(data.allVoxel.Length);
                    for (int m = 0; m < data.allVoxel.Length; m++)
                    {
                        VoxelUnitData unit = data.allVoxel[m];
                        bw.Write(unit.name);
                        Vector3Int v = unit.size;
                        bw.Write(v.x);//X长度
                        bw.Write(v.y);//Y长度
                        bw.Write(v.z);//Z长度

                        Vector3 v3 = unit.zero;
                        bw.Write(v3.x);
                        bw.Write(v3.y);
                        bw.Write(v3.z);

                        v3 = unit.world;
                        bw.Write(v3.x);
                        bw.Write(v3.y);
                        bw.Write(v3.z);

                        v3 = unit.min;
                        bw.Write(v3.x);
                        bw.Write(v3.y);
                        bw.Write(v3.z);
                        
                        byte[] voxel = unit.voxelData;
                        int size = v.x * v.y * v.z;
                        for (int i = 0; i < size; i++)
                        {
                            bw.Write(voxel[i]);
                        }
                    }

                }
            }
        }

        public static RioVoxelData Open(string path)
        {
            using (FileStream _ms = new FileStream(path, FileMode.Open))
            {
                using (BinaryReader br = new BinaryReader(_ms))
                {
                    string name = br.ReadString();
                    if (name.Equals("riovox") == false)
                    {
                        return new RioVoxelData(false);
                    }
                    string version = br.ReadString();

                    int headLength = br.ReadInt32();

                    VoxelHeadData[] headDatas = new VoxelHeadData[headLength];
                    for (int i = 0; i < headLength; i++)
                    {
                        VoxelHeadData headData = new VoxelHeadData();
                        headData.operationType = br.ReadString();
                        bool isok = br.ReadBoolean();
                        headData.isOpen = isok;
                        if (isok)
                        {
                            headData.operationData = br.ReadString();
                        }
                        headDatas[i] = headData;
                    }


                    int allLength = br.ReadInt32();

                    if (allLength > 0)
                    {

                    }

                    int colorLength = br.ReadInt32();
                    Color32[] colors = new Color32[colorLength];
                    for (int i = 0; i < colorLength; i++)
                    {
                        byte r = br.ReadByte();
                        byte g = br.ReadByte();
                        byte b = br.ReadByte();
                        Color32 color = new Color32(r, g, b , 255);
                        colors[i] = color;
                    }

                    //材质
                    int materialDataLength = br.ReadInt32();
                    if (materialDataLength == -2)
                    {

                    }
                    int boneLength = br.ReadInt32();


                    VoxelBoneTransform[] tranforms = new VoxelBoneTransform[boneLength];
                    int[] nowTranformIndexs = new int[boneLength];//索引是layer层，数据是改层当前的index索引

                    for (int i = 0; i < boneLength; i++)
                    {
                        string tranformName = br.ReadString();
                        int tranformlayer = br.ReadInt32();
                        VoxelBoneTransform tranform = new VoxelBoneTransform(tranformName, i);
                        tranforms[i] = tranform;

                        nowTranformIndexs[tranformlayer] = i;
                        if (tranformlayer > 0)
                        {
                            tranform.parentIndex = nowTranformIndexs[tranformlayer - 1];
                            tranform.parent = tranforms[tranform.parentIndex];
                        }
                    }

                    
                    //中心点的坐标
                    for (int m = 0; m < boneLength; m++)
                    {
                        float x = br.ReadSingle();
                        float y = br.ReadSingle();
                        float z = br.ReadSingle();
                        tranforms[m].pivot = new Vector3(x, y, z);
                    }

                    //相对父对象的坐标
                    for (int m = 0; m < boneLength; m++)
                    {
                        float x = br.ReadSingle();
                        float y = br.ReadSingle();
                        float z = br.ReadSingle();
                        tranforms[m].localPosition = new Vector3(x, y, z);
                    }

                    //相对父对象的旋转欧拉角
                    for (int m = 0; m < boneLength; m++)
                    {
                        float x = br.ReadSingle();
                        float y = br.ReadSingle();
                        float z = br.ReadSingle();
                        tranforms[m].localEulerAngles = new Vector3(x, y, z);
                    }

                    //相对父对象的缩放
                    for (int m = 0; m < boneLength; m++)
                    {
                        float x = br.ReadSingle();
                        float y = br.ReadSingle();
                        float z = br.ReadSingle();
                        tranforms[m].localScale = new Vector3(x, y, z);
                    }

                    //蒙皮参数
                    int skinDataLength = br.ReadInt32();
                    if (skinDataLength > 0)
                    {

                    }

                    int voxelUnitLength = br.ReadInt32();
                    VoxelUnitData[] allVoxel = new VoxelUnitData[voxelUnitLength];
                    for (int m = 0; m < voxelUnitLength; m++)
                    {
                        VoxelUnitData unit = new VoxelUnitData();
                        unit.name = br.ReadString();
                        int x = br.ReadInt32();//X长度
                        int y = br.ReadInt32();//Y长度
                        int z = br.ReadInt32();//Z长度
                        int size = x * y * z;
                        unit.size = new Vector3Int(x, y, z);


                        float fx = br.ReadSingle();
                        float fy = br.ReadSingle();
                        float fz = br.ReadSingle();
                        Vector3 v3 = new Vector3(fx, fy, fz);
                        unit.zero = v3;

                        fx = br.ReadSingle();
                        fy = br.ReadSingle();
                        fz = br.ReadSingle();
                        v3 = new Vector3(fx, fy, fz);
                        unit.world = v3;

                        fx = br.ReadSingle();
                        fy = br.ReadSingle();
                        fz = br.ReadSingle();
                        v3 = new Vector3(fx, fy, fz);
                        unit.min = v3;

                        byte[] voxel = new byte[size];
                        for (int i = 0; i < size; i++)
                        {
                            voxel[i] = br.ReadByte();
                        }
                        unit.voxelData = voxel;
                        allVoxel[m] = unit;
                    }


                    RioVoxelData riovox = new RioVoxelData(true);
                    riovox.colors = colors;
                    riovox.transforms = tranforms;
                    riovox.allVoxel = allVoxel;
                    riovox.headDatas = headDatas;
                    riovox.version = version;

                    return riovox;
                }
            }
        }

    }
}
